//============================================================================
// Name        : ControlShell.cpp
// Author      : Minfang
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <iostream>
#include <fstream>
#include <stdio.h>

#include <stdlib.h>
#include <string.h>
#include <pty.h>
#include <stdio.h>
#include <unistd.h>
#include <utmp.h>
#include <pthread.h>
#include <fcntl.h>
#include <time.h>
#include <unistd.h>
#include <errno.h>
using namespace std;

void startChild(int argc, char ** argv);
ofstream log;
bool comeLogFlag = false, sendLogFlag = false;
int fdd;

bool exitFlag;

void *writng_message_function(void *ptr) {

	char c;
	struct timespec req, rem;

	req.tv_nsec = 100000000;
	req.tv_sec = 0;

	while (true) {
		//scout<<"get ["<<c<<"] ";

		int rl = read(fdd, &c, 1);

		if (rl == 0) {

			break;
		} else if (rl == -1) {

			//sleep

			if (errno == EAGAIN) {
				nanosleep(&req, &rem);

				continue;
			} else {
				//other error!
				break;
			}
		}

		else if (rl != 1) {

			break;
		}

		if (exitFlag) {
			break;
		}
		write(1, &c, 1);

		if (comeLogFlag) {
			log << c;
		}

	}

	exitFlag = true;

	return NULL;
}
int main(int argc, char ** argv) {

	int argLen = argc;
	if (argc > 2) {
		// log send, come, or both
		if (strcmp(argv[argc - 2], "-tbgilog") == 0) {
			log.open(argv[argc - 1], ofstream::app);
			if (log.is_open()) {
				comeLogFlag = true;
			}
			argLen -= 2;
		} else if (strcmp(argv[argc - 2], "-tbgolog") == 0) {
			log.open(argv[argc - 1], ofstream::app);
			if (log.is_open()) {
				sendLogFlag = true;
			}
			argLen -= 2;
		} else if (strcmp(argv[argc - 2], "-tbgiolog") == 0) {
			log.open(argv[argc - 1], ofstream::app);
			if (log.is_open()) {
				sendLogFlag = true;
				comeLogFlag = true;
			}
			argLen -= 2;
		}

	}

	if (argc < 2) {
		cerr << "nothing to run!" << endl;
		exit(1);
	}

	exitFlag = false;
	pid_t pid;

	pid = forkpty(&fdd, 0, 0, 0);

	if (pid == 0) {

		startChild(argLen, argv);

		exit(1);
	} else if (pid == -1) {
		perror("forkpty wrong:");

		exit(1);
	} else {

		fcntl(fdd, F_SETFL, O_NONBLOCK);
		fcntl(0, F_SETFL, O_NONBLOCK);

		pthread_t writeThread;

		pthread_create(&writeThread, NULL, writng_message_function, NULL);

		struct timespec req, rem;

		req.tv_nsec = 100000000;
		req.tv_sec = 0;
		char c;

		while (true) {
			if (exitFlag) {
				break;
			}
			int rl = read(0, &c, 1);

			if (rl == 0) {
				break;
			}

			else if (rl == -1) {
				//sleep

				if (errno == EAGAIN) {
					nanosleep(&req, &rem);

					continue;
				} else {
					//other error!
					break;
				}
			} else if (rl != 1) {
				break;
			}

			write(fdd, &c, 1);

			if (sendLogFlag) {
				log << c;
			}

		}
		exitFlag = true;
		close(fdd);

		pthread_join(writeThread, NULL);

		if (sendLogFlag || comeLogFlag) {
			log.close();
		}

	}

}
/*
 *  php code for generate startChild function


<?php

$size=100;
if(count($argv) >1){
	$size=intval($argv[1]);
}

echo "#include <unistd.h>\n\n";
echo "#include <iostream>\n\n";
echo "using namespace std;\n\n";

echo "void startChild(int argc, char ** argv) {\n";
$limit=$size-1;
echo "\tif(argc > {$limit}){\n";
echo "\t\t// can not handle parameters more than 299\n";
echo "\t\tcerr<<argc<<\" parameter is too much for the program, limit is \"<<$limit<<endl;\n";
echo "\t\treturn ;\n";
echo "\t}\n";


echo "\tswitch (argc) {\n";

for($i1 =2;$i1<$size;$i1++){

	echo "\tcase {$i1}:\n";

	echo "\t\texeclp(argv[1], ";

	for($i2=1;$i2<$i1;$i2++){
		echo "argv[{$i2}],";
	}
	echo "(void *) 0);\n\t\tbreak;\n";

}

echo "\t}\n}\n";

?>


 */

/*

 Generate the code:


php a.php 300 > ~/c_plus_project/TtyBridge/startChild.cpp
 */
